package controllers

import (
	"encoding/json"
	"fmt"
	"log"
	"reflect"
	"sync"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"gopkg.in/fatih/set.v0"
)

type ChatController struct {
	BaseController
}

const (
	CMD_SINGLE_MSG = 10
	CMD_ROOM_MSG   = 11
	CMD_HEART      = 0
)

type Message struct {
	Id      int64  `json:"id,omitempty" form:"id"`           //消息ID
	Userid  int64  `json:"userid,omitempty" form:"userid"`   //谁发的
	Cmd     int    `json:"cmd,omitempty" form:"cmd"`         //群聊还是私聊
	Dstid   int64  `json:"dstid,omitempty" form:"dstid"`     //对端用户ID/群ID
	Media   int    `json:"media,omitempty" form:"media"`     //消息按照什么样式展示
	Content string `json:"content,omitempty" form:"content"` //消息的内容
	Pic     string `json:"pic,omitempty" form:"pic"`         //预览图片
	Url     string `json:"url,omitempty" form:"url"`         //服务的URL
	Memo    string `json:"memo,omitempty" form:"memo"`       //简单描述
	Amount  int    `json:"amount,omitempty" form:"amount"`   //其他和数字相关的
}

// 本核心在于形成userid和Node的映射关系
type Node struct {
	Conn *websocket.Conn
	//并行转串行,
	DataQueue chan []byte
	GroupSets set.Interface
}

// 映射关系表
var clientMap map[int64]*Node = make(map[int64]*Node, 0)

// 读写锁
var rwlocker sync.RWMutex

func (con ChatController) Index(c *gin.Context, conn *websocket.Conn) {

	// 在处理程序中使用c.Get获取值
	if userId, exists := c.Get("userId"); exists {

		userIdInt64, err := ConvertToInt64(userId)
		if err != nil {
			fmt.Println("Error:", err)
			return
		}

		fmt.Println("执行了一次消息发送也是C")
		//todo 获得conn
		node := &Node{
			Conn:      conn,
			DataQueue: make(chan []byte, 50),
			GroupSets: set.New(set.ThreadSafe),
		}

		//todo userid和node形成绑定关系
		rwlocker.Lock()
		clientMap[userIdInt64] = node
		rwlocker.Unlock()

		fmt.Println("执行了一次消息发送也是D")

		//todo 完成发送逻辑,con
		go sendproc(node)
		//todo 完成接收逻辑
		go recvproc(node)
		//
		fmt.Println("执行了一次消息发送也是")
		sendMsg(userIdInt64, []byte("hello,world!"))
	}
}

func ConvertToInt64(data interface{}) (int64, error) {
	switch v := data.(type) {
	case int:
		return int64(v), nil
	case int64:
		return v, nil
	case float32:
		return int64(v), nil
	case float64:
		return int64(v), nil
	default:
		return 0, fmt.Errorf("unsupported data type: %v", reflect.TypeOf(data))
	}
}

// 发送协程
func sendproc(node *Node) {
	for data := range node.DataQueue {
		err := node.Conn.WriteMessage(websocket.TextMessage, data)
		if err != nil {
			log.Println(err.Error())
			return
		}
	}
}

// 接收协程
func recvproc(node *Node) {
	for {
		_, data, err := node.Conn.ReadMessage()
		if err != nil {
			log.Println(err.Error())
			return
		}
		//todo 对data进一步处理
		dispatch(data)
		fmt.Printf("recv<=%s", data)
	}
}

// 后端调度逻辑处理
func dispatch(data []byte) {
	//todo 解析data为message
	msg := Message{}
	err := json.Unmarshal(data, &msg)
	if err != nil {
		log.Println(err.Error())
		return
	}
	//todo 根据cmd对逻辑进行处理
	switch msg.Cmd {
	case CMD_SINGLE_MSG:
		sendMsg(msg.Dstid, data)
	case CMD_ROOM_MSG:
		//todo 群聊转发逻辑
	case CMD_HEART:
		//todo 一般啥都不做
	}
}

// todo 发送消息
func sendMsg(userId int64, msg []byte) {
	fmt.Println("执行了一次消息发送也是E")
	rwlocker.RLock()
	node, ok := clientMap[userId]
	rwlocker.RUnlock()
	if ok {
		node.DataQueue <- msg
	}
}
